#include "RedisManager.h"


RedisManager::RedisManager()
{
	auto& gCfgMgr = ConfigManager::getInstance();
	auto host = gCfgMgr["Redis"]["Host"];
	auto port = gCfgMgr["Redis"]["Port"];
	auto pwd = gCfgMgr["Redis"]["Passwd"];
	m_con_pool.reset(new RedisConnectionPool(5, host.c_str(), atoi(port.c_str()), pwd.c_str()));
}


// 获取key对应的value
bool RedisManager::get(const std::string& key, std::string& value)
{
	auto connect = m_con_pool->getConnection();
	if (connect == nullptr) {
		return false;
	}

	auto reply = (redisReply*)redisCommand(connect, "GET %s", key.c_str());
	if (reply == NULL) {
		std::cout << "[ GET  " << key << " ] failed" << std::endl;
		// freeReplyObject(reply);
		m_con_pool->returnConnection(connect);
		return false;
	}

	if (reply->type != REDIS_REPLY_STRING) {
		std::cout << "[ GET  " << key << " ] failed" << std::endl;
		freeReplyObject(reply);
		m_con_pool->returnConnection(connect);
		return false;
	}

	value = reply->str;
	freeReplyObject(reply);

	std::cout << "Succeed to execute command [ GET " << key << "  ]" << std::endl;
	m_con_pool->returnConnection(connect);

	return true;
}

// 设置key和value
bool RedisManager::set(const std::string& key, const std::string& value)
{
	// 执行redis命令行
	auto connect = m_con_pool->getConnection();
	if (connect == nullptr) {
		return false;
	}

	auto reply = (redisReply*)redisCommand(connect, "SET %s %s", key.c_str(), value.c_str());
	// 如果返回NULL则说明执行失败
	if (reply == NULL)
	{
		std::cout << "Execut command [ SET " << key << "  " << value << " ] failure ! " << std::endl;
		// freeReplyObject(reply);
		m_con_pool->returnConnection(connect);
		return false;
	}

	// 如果执行失败则释放连接
	if (!(reply->type == REDIS_REPLY_STATUS && (strcmp(reply->str, "OK") == 0 || strcmp(reply->str, "ok") == 0)))
	{
		std::cout << "Execut command [ SET " << key << "  " << value << " ] failure ! " << std::endl;
		freeReplyObject(reply);
		m_con_pool->returnConnection(connect);
		return false;
	}

	// 执行成功 释放redisCommand执行后返回的redisReply所占用的内存
	freeReplyObject(reply);
	std::cout << "Execut command [ SET " << key << "  " << value << " ] success ! " << std::endl;
	m_con_pool->returnConnection(connect);
	return true;
}

// 密码校验
bool RedisManager::auth(const std::string& password)
{
	auto connect = m_con_pool->getConnection();
	if (connect == nullptr) {
		return false;
	}

	auto reply = (redisReply*)redisCommand(connect, "AUTH %s", password.c_str());
	if (reply->type == REDIS_REPLY_ERROR) {
		std::cout << "认证失败" << std::endl;
		// 执行成功 释放redisCommand执行后返回的redisReply所占用的内存
		freeReplyObject(reply);
		m_con_pool->returnConnection(connect);
		return false;
	}
	else {
		// 执行成功 释放redisCommand执行后返回的redisReply所占用的内存
		freeReplyObject(reply);
		std::cout << "认证成功" << std::endl;
		m_con_pool->returnConnection(connect);
		return true;
	}
}

// 左侧push
bool RedisManager::lPush(const std::string& key, const std::string& value)
{
	auto connect = m_con_pool->getConnection();
	if (connect == nullptr) {
		return false;
	}
	auto reply = (redisReply*)redisCommand(connect, "LPUSH %s %s", key.c_str(), value.c_str());
	if (reply == NULL)
	{
		std::cout << "Execut command [ LPUSH " << key << "  " << value << " ] failure ! " << std::endl;
		freeReplyObject(reply);
		m_con_pool->returnConnection(connect);
		return false;
	}

	if (reply->type != REDIS_REPLY_INTEGER || reply->integer <= 0) {
		std::cout << "Execut command [ LPUSH " << key << "  " << value << " ] failure ! " << std::endl;
		freeReplyObject(reply);
		m_con_pool->returnConnection(connect);
		return false;
	}

	std::cout << "Execut command [ LPUSH " << key << "  " << value << " ] success ! " << std::endl;
	freeReplyObject(reply);
	m_con_pool->returnConnection(connect);
	return true;
}

// 左侧pop
bool RedisManager::lPop(const std::string& key, std::string& value)
{
	auto connect = m_con_pool->getConnection();
	if (connect == nullptr) {
		return false;
	}
	auto reply = (redisReply*)redisCommand(connect, "LPOP %s ", key.c_str());
	if (reply == nullptr) {
		std::cout << "Execut command [ LPOP " << key << " ] failure ! " << std::endl;
		// freeReplyObject(reply);
		m_con_pool->returnConnection(connect);
		return false;
	}

	if (reply->type == REDIS_REPLY_NIL) {
		std::cout << "Execut command [ LPOP " << key << " ] failure ! " << std::endl;
		freeReplyObject(reply);
		m_con_pool->returnConnection(connect);
		return false;
	}

	value = reply->str;
	std::cout << "Execut command [ LPOP " << key << " ] success ! " << std::endl;
	freeReplyObject(reply);
	m_con_pool->returnConnection(connect);
	return true;
}

// 右侧push
bool RedisManager::rPush(const std::string& key, const std::string& value)
{
	auto connect = m_con_pool->getConnection();
	if (connect == nullptr) {
		return false;
	}
	auto reply = (redisReply*)redisCommand(connect, "RPUSH %s %s", key.c_str(), value.c_str());
	if (reply == NULL)
	{
		std::cout << "Execut command [ RPUSH " << key << "  " << value << " ] failure ! " << std::endl;
		freeReplyObject(reply);
		m_con_pool->returnConnection(connect);
		return false;
	}

	if (reply->type != REDIS_REPLY_INTEGER || reply->integer <= 0) {
		std::cout << "Execut command [ RPUSH " << key << "  " << value << " ] failure ! " << std::endl;
		freeReplyObject(reply);
		m_con_pool->returnConnection(connect);
		return false;
	}

	std::cout << "Execut command [ RPUSH " << key << "  " << value << " ] success ! " << std::endl;
	freeReplyObject(reply);
	m_con_pool->returnConnection(connect);
	return true;
}

// 右侧pop
bool RedisManager::rPop(const std::string& key, std::string& value)
{
	auto connect = m_con_pool->getConnection();
	if (connect == nullptr) {
		return false;
	}
	auto reply = (redisReply*)redisCommand(connect, "RPOP %s ", key.c_str());
	if (reply == nullptr) {
		std::cout << "Execut command [ RPOP " << key << " ] failure ! " << std::endl;
		// freeReplyObject(reply);
		m_con_pool->returnConnection(connect);
		return false;
	}

	if (reply->type == REDIS_REPLY_NIL) {
		std::cout << "Execut command [ RPOP " << key << " ] failure ! " << std::endl;
		freeReplyObject(reply);
		m_con_pool->returnConnection(connect);
		return false;
	}

	value = reply->str;
	std::cout << "Execut command [ RPOP " << key << " ] success ! " << std::endl;
	freeReplyObject(reply);
	m_con_pool->returnConnection(connect);
	return true;
}

// HSet操作
bool RedisManager::hSet(const std::string& key, const std::string& hkey, const std::string& value)
{
	auto connect = m_con_pool->getConnection();
	if (connect == nullptr) {
		return false;
	}
	auto reply = (redisReply*)redisCommand(connect, "HSET %s %s %s", key.c_str(), hkey.c_str(), value.c_str());
	if (reply == nullptr) {
		std::cout << "Execut command [ HSet " << key << "  " << hkey << "  " << value << " ] failure ! " << std::endl;
		// freeReplyObject(reply);
		m_con_pool->returnConnection(connect);
		return false;
	}

	if (reply->type != REDIS_REPLY_INTEGER) {
		std::cout << "Execut command [ HSet " << key << "  " << hkey << "  " << value << " ] failure ! " << std::endl;
		freeReplyObject(reply);
		m_con_pool->returnConnection(connect);
		return false;
	}

	std::cout << "Execut command [ HSet " << key << "  " << hkey << "  " << value << " ] success ! " << std::endl;
	freeReplyObject(reply);
	m_con_pool->returnConnection(connect);
	return true;
}

bool RedisManager::hSet(const char* key, const char* hkey, const char* hvalue, size_t hvaluelen)
{
	auto connect = m_con_pool->getConnection();
	if (connect == nullptr) {
		return false;
	}
	const char* argv[4];
	size_t argvlen[4];
	argv[0] = "HSET";
	argvlen[0] = 4;
	argv[1] = key;
	argvlen[1] = strlen(key);
	argv[2] = hkey;
	argvlen[2] = strlen(hkey);
	argv[3] = hvalue;
	argvlen[3] = hvaluelen;

	auto reply = (redisReply*)redisCommandArgv(connect, 4, argv, argvlen);
	if (reply == nullptr) {
		std::cout << "Execut command [ HSet " << key << "  " << hkey << "  " << hvalue << " ] failure ! " << std::endl;
		// freeReplyObject(reply);
		m_con_pool->returnConnection(connect);
		return false;
	}

	if (reply->type != REDIS_REPLY_INTEGER) {
		std::cout << "Execut command [ HSet " << key << "  " << hkey << "  " << hvalue << " ] failure ! " << std::endl;
		freeReplyObject(reply);
		m_con_pool->returnConnection(connect);
		return false;
	}

	std::cout << "Execut command [ HSet " << key << "  " << hkey << "  " << hvalue << " ] success ! " << std::endl;
	freeReplyObject(reply);
	m_con_pool->returnConnection(connect);
	return true;
}

// hDel操作
bool RedisManager::hDel(const std::string& key, const std::string& field)
{
	auto connect = m_con_pool->getConnection();
	if (connect == nullptr) {
		return false;
	}

	Defer defer([&connect, this]() {
		m_con_pool->returnConnection(connect);
	});

	redisReply* reply = (redisReply*)redisCommand(connect, "HDEL %s %s", key.c_str(), field.c_str());
	if (reply == nullptr) {
		std::cerr << "HDEL command failed" << std::endl;
		return false;
	}

	bool success = false;
	if (reply->type == REDIS_REPLY_INTEGER) {
		success = reply->integer > 0;
	}

	freeReplyObject(reply);
	return success;
}

// HGet操作
std::string RedisManager::hGet(const std::string& key, const std::string& hkey)
{
	auto connect = m_con_pool->getConnection();
	if (connect == nullptr) {
		return "";
	}
	const char* argv[3];
	size_t argvlen[3];
	argv[0] = "HGET";
	argvlen[0] = 4;
	argv[1] = key.c_str();
	argvlen[1] = key.length();
	argv[2] = hkey.c_str();
	argvlen[2] = hkey.length();

	auto reply = (redisReply*)redisCommandArgv(connect, 3, argv, argvlen);
	if (reply == nullptr) {
		// freeReplyObject(reply);
		std::cout << "Execut command [ HGet " << key << " " << hkey << "  ] failure ! " << std::endl;
		m_con_pool->returnConnection(connect);
		return "";
	}

	if (reply->type == REDIS_REPLY_NIL) {
		freeReplyObject(reply);
		std::cout << "Execut command [ HGet " << key << " " << hkey << "  ] failure ! " << std::endl;
		m_con_pool->returnConnection(connect);
		return "";
	}

	std::string value = reply->str;
	freeReplyObject(reply);
	std::cout << "Execut command [ HGet " << key << " " << hkey << " ] success ! " << std::endl;
	m_con_pool->returnConnection(connect);
	return value;
}

// Del 操作
bool RedisManager::del(const std::string& key)
{
	auto connect = m_con_pool->getConnection();
	if (connect == nullptr) {
		return false;
	}
	auto reply = (redisReply*)redisCommand(connect, "DEL %s", key.c_str());
	if (reply == nullptr) {
		std::cout << "Execut command [ Del " << key << " ] failure ! " << std::endl;
		// freeReplyObject(reply);
		m_con_pool->returnConnection(connect);
		return false;
	}

	if (reply->type != REDIS_REPLY_INTEGER) {
		std::cout << "Execut command [ Del " << key << " ] failure ! " << std::endl;
		freeReplyObject(reply);
		m_con_pool->returnConnection(connect);
		return false;
	}

	std::cout << "Execut command [ Del " << key << " ] success ! " << std::endl;
	freeReplyObject(reply);
	m_con_pool->returnConnection(connect);
	return true;
}

// 判断键值是否存在
bool RedisManager::existsKey(const std::string& key)
{
	auto connect = m_con_pool->getConnection();
	if (connect == nullptr) {
		return false;
	}
	auto reply = (redisReply*)redisCommand(connect, "exists %s", key.c_str());
	if (reply == nullptr) {
		std::cout << "Not Found [ Key " << key << " ]  ! " << std::endl;
		// freeReplyObject(reply);
		m_con_pool->returnConnection(connect);
		return false;
	}

	if (reply->type != REDIS_REPLY_INTEGER || reply->integer == 0) {
		std::cout << "Not Found [ Key " << key << " ]  ! " << std::endl;
		m_con_pool->returnConnection(connect);
		freeReplyObject(reply);
		return false;
	}

	std::cout << " Found [ Key " << key << " ] exists ! " << std::endl;
	freeReplyObject(reply);
	m_con_pool->returnConnection(connect);
	return true;
}

// 关闭Redis连接池
void RedisManager::close()
{
	m_con_pool->close();
	m_con_pool->clearConnection();	
}

RedisConnectionPool::RedisConnectionPool(size_t poolSize, const char* host, unsigned short port, const char* pwd)
	: m_pool_size(poolSize), m_host(host), m_port(port), m_b_stop(false), m_pwd(pwd)
{
	for (size_t i = 0; i < m_pool_size; ++i) {
		auto* context = redisConnect(host, port);
		if (context == nullptr || context->err != 0) {
			if (context != nullptr) {
				redisFree(context);
			}
			continue;
		}

		auto reply = (redisReply*)redisCommand(context, "AUTH %s", pwd);
		if (reply->type == REDIS_REPLY_ERROR) {
			std::cout << "认证失败" << std::endl;
			// 执行成功 释放redisCommand执行后返回的redisReply所占用的内存
			freeReplyObject(reply);
			continue;
		}

		//执行成功 释放redisCommand执行后返回的redisReply所占用的内存
		freeReplyObject(reply);
		std::cout << "认证成功" << std::endl;
		m_connections.push(context);
	}

	m_check_thread = std::thread([this]() {
		auto last_check_time = std::chrono::steady_clock::now();
		while (!m_b_stop) {
			auto now = std::chrono::steady_clock::now();
			auto elapsed_seconds = std::chrono::duration_cast<std::chrono::seconds>(now - last_check_time).count();

			if (elapsed_seconds >= 60) { // 每隔 60 秒执行一次 checkThread
				checkThread();
				last_check_time = std::chrono::steady_clock::now(); // 更新最后检查时间
			}

			std::this_thread::sleep_for(std::chrono::seconds(10)); // 每隔 10 秒唤醒一次
		}
	});
}

redisContext* RedisConnectionPool::getConnection()
{
	std::unique_lock<std::mutex> lock(m_mutex);
	m_cond.wait(lock, [this] {
		if (m_b_stop) {
			return true;
		}
		return !m_connections.empty();
		});
	// 如果停止则直接返回空指针
	if (m_b_stop) {
		return nullptr;
	}

	auto* context = m_connections.front();
	m_connections.pop();
	return context;
}

void RedisConnectionPool::returnConnection(redisContext* context)
{
	std::lock_guard<std::mutex> lock(m_mutex);
	if (m_b_stop) {
		return;
	}
	m_connections.push(context);
	m_cond.notify_one();
}

void RedisConnectionPool::clearConnection()
{
	std::lock_guard<std::mutex> lock(m_mutex);
	while (!m_connections.empty()) {
		auto* context = m_connections.front();
		redisFree(context);
		m_connections.pop();
	}
}

void RedisConnectionPool::close()
{
	m_b_stop = true;
	m_cond.notify_all();
	m_check_thread.join();
}

// 检测Redis连接的线程执行函数
void RedisConnectionPool::checkThread()
{
	std::lock_guard<std::mutex> lock(m_mutex);
	if (m_b_stop) {
		return;
	}
	auto pool_size = m_connections.size();
	for (int i = 0; i < pool_size && !m_b_stop; i++) {
		auto* context = m_connections.front();
		m_connections.pop();
		try {
			auto reply = (redisReply*)redisCommand(context, "PING");
			if (!reply) {
				std::cout << "reply is null, redis ping failed: " << std::endl;
				m_connections.push(context);
				continue;
			}
			freeReplyObject(reply);
			m_connections.push(context);
		}
		catch (const std::exception& exp) {
			std::cout << "Error keeping connection alive: " << exp.what() << std::endl;
			redisFree(context);
			context = redisConnect(m_host, m_port);
			if (context == nullptr || context->err != 0) {
				if (context != nullptr) {
					redisFree(context);
				}
				continue;
			}

			auto reply = (redisReply*)redisCommand(context, "AUTH %s", m_pwd);
			if (reply->type == REDIS_REPLY_ERROR) {
				std::cout << "认证失败" << std::endl;
				//执行成功 释放redisCommand执行后返回的redisReply所占用的内存
				freeReplyObject(reply);
				continue;
			}

			// 执行成功 释放redisCommand执行后返回的redisReply所占用的内存
			freeReplyObject(reply);
			std::cout << "认证成功" << std::endl;
			m_connections.push(context);
		}
	}
}
